/**
 * 
 */
package fhq.hcmute.qrcode.detector.util;

import fhq.hcmute.qrcode.common.BinaryImage;
import fhq.hcmute.qrcode.common.BitMatrix;
import fhq.hcmute.qrcode.util.QRCodeException;
import static fhq.hcmute.qrcode.util.QRCodeException.*;
/**
 * @author Hien Nguyen Le
 * @Email: nglehien@gmail.com
 */
public class QRCodeSample {
	public BitMatrix sampleGrid(BinaryImage image, int dimensionX,
			int dimensionY, ImageTransform transform) throws QRCodeException {
		if (dimensionX <= 0 || dimensionY <= 0) {
			throw new QRCodeException(QR_CODE_NOT_FOUND);
		}
		BitMatrix bits = new BitMatrix(dimensionX, dimensionY);
		float[] points = new float[dimensionX << 1];
		for (int y = 0; y < dimensionY; y++) {
			int max = points.length;
			float iValue = (float) y + 0.5f;
			for (int x = 0; x < max; x += 2) {
				points[x] = (float) (x >> 1) + 0.5f;
				points[x + 1] = iValue;
			}
			transform.transformPoints(points);
			checkAndNudgePoints(image, points);
			for (int x = 0; x < max; x += 2) {
				if (image.getPixel((int) points[x + 1], (int) points[x])) {
					bits.set(y, x >> 1, BitMatrix.TRUE);
				} else {
					bits.set(y, x >> 1, BitMatrix.FALSE);
				}
			}
		}
		return bits;
	}

	private void checkAndNudgePoints(BinaryImage image, float[] points)
			throws QRCodeException {
		int width = image.getWidth();
		int height = image.getHeight();
		// Check and nudge points from start until we see some that are OK:
		boolean nudged = true;
		for (int offset = 0; offset < points.length && nudged; offset += 2) {
			int x = (int) points[offset];
			int y = (int) points[offset + 1];
			if (x < -1 || x > width || y < -1 || y > height) {
				throw new QRCodeException(INVALID_POINT);
			}
			nudged = false;
			if (x == -1) {
				points[offset] = 0.0f;
				nudged = true;
			} else if (x == width) {
				points[offset] = width - 1;
				nudged = true;
			}
			if (y == -1) {
				points[offset + 1] = 0.0f;
				nudged = true;
			} else if (y == height) {
				points[offset + 1] = height - 1;
				nudged = true;
			}
		}
		// Check and nudge points from end:
		nudged = true;
		for (int offset = points.length - 2; offset >= 0 && nudged; offset -= 2) {
			int x = (int) points[offset];
			int y = (int) points[offset + 1];
			if (x < -1 || x > width || y < -1 || y > height) {
				throw new QRCodeException(INVALID_POINT);
			}
			nudged = false;
			if (x == -1) {
				points[offset] = 0.0f;
				nudged = true;
			} else if (x == width) {
				points[offset] = width - 1;
				nudged = true;
			}
			if (y == -1) {
				points[offset + 1] = 0.0f;
				nudged = true;
			} else if (y == height) {
				points[offset + 1] = height - 1;
				nudged = true;
			}
		}
	}
}
